/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean.MrpMrp;

import java.sql.Timestamp;
import merlion.mrp.ppm.pojo.LongHolder;
import java.util.ArrayList;
import java.util.Calendar;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import merlion.common.util.Consts;
import merlion.mrp.ppm.entity.MRP;
import merlion.mrp.ppm.session.MPSPlanningSessionLocal;
import merlion.mrp.ppm.session.MRPSessionLocal;

/**
 *
 * @author Zhang Ying
 */
@ManagedBean
@ViewScoped
public class MrpMrpEditManagerBean {

    @EJB
    private MRPSessionLocal mrpSession;
    @EJB
    private MPSPlanningSessionLocal mpsSession;
    private ArrayList<Integer> counterForProduct;
    private ArrayList<Integer> counterForWeek;
    private MRP selectedMRP;
    private ArrayList<ArrayList<Long>> weeklyDemands;
    private ArrayList<LongHolder> inputLotNumbers;
    private Integer numOfWks;
    ArrayList<ArrayList<Timestamp>> startEndDays;

    /** Creates a new instance of MrpMrpEditManagerBean */
    public MrpMrpEditManagerBean() {
        counterForProduct = new ArrayList<Integer>();
        for (int i = 0; i < 4; i++) {
            counterForProduct.add(i);
        }
        counterForWeek = new ArrayList<Integer>();
        for (int i = 0; i < 5; i++) {
            counterForWeek.add(i);
        }
    }

    public String confirmMrp() {
        for (int i = 0; i < numOfWks; i++) {
            if (selectedMRP.getGrossRequirements().get(i).getLongValue() < 0
                    || selectedMRP.getPlannedInventory().get(i).getLongValue() < 0
                    || selectedMRP.getPlannedReceipts().get(i).getLongValue() < 0) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                        "Sorry. On hand inventory cannot be negative. Please check week" + (i + 1) + " for material " + selectedMRP.getBom().getMaterial().getName()));
                return null;
            }
        }
        // persist mrp into database
        if (mrpSession.updateMRP(selectedMRP)) {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(MrpMrpViewManagerBean.EDIT_MRP);
            return getRedirectPath(Consts.EDIT_MRP_MRP_PATH + "Confirm");
        } else {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                    "not able to persist into the database"));
            return null;
        }
    }

    public void autoOptimization(ActionEvent event) {
        for (int i = 0; i < numOfWks; i++) {
            Long inv = selectedMRP.getPlannedInventory().get(i).getLongValue();
            if (inv < 0) {
                inv = Math.abs(inv);
                Long numOfLots;
                if (inv % selectedMRP.getBom().getMaterial().getLotSize() == 0) {
                    numOfLots = inv / selectedMRP.getBom().getMaterial().getLotSize();
                } else {
                    numOfLots = inv / selectedMRP.getBom().getMaterial().getLotSize() + 1;
                }
                Long prevRec = selectedMRP.getPlannedReceipts().get(i).getLongValue();
                Long currentPlannedReceipt = prevRec + numOfLots * selectedMRP.getBom().getMaterial().getLotSize();
                selectedMRP.getPlannedReceipts().get(i).setLongValue(currentPlannedReceipt);
                inputLotNumbers.get(i).setL(numOfLots + prevRec / selectedMRP.getBom().getMaterial().getLotSize());
                for (int j = i; j < numOfWks; j++) {
                    Long prevInv;
                    if (j == 0) {
                        prevInv = mrpSession.getPlannedInventoryForPrevWeek(selectedMRP.getStartPeriodYear(), selectedMRP.getStartPeriodMonth(), selectedMRP.getBom());
                    } else {
                        prevInv = selectedMRP.getPlannedInventory().get(j - 1).getLongValue();
                    }
                    Long currentInv = prevInv + selectedMRP.getPlannedReceipts().get(j).getLongValue() - selectedMRP.getGrossRequirements().get(j).getLongValue();
                    selectedMRP.getPlannedInventory().get(j).setLongValue(currentInv);
                }
            }
        }
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Successful",
                "Filled in for this materials done."));
    }

    public void autoOptimizationWSafetyStock(ActionEvent event) {
        for (int i = 0; i < numOfWks; i++) {
            Long inv = selectedMRP.getPlannedInventory().get(i).getLongValue();
            // need to get safety stock from scm
            Long safteStock = mrpSession.getRawMaterialSafetyStockFromSCM(selectedMRP.getBom().getMaterial().getName());
            inv = inv - safteStock;
            if (inv < 0) {
                inv = Math.abs(inv);
                Long numOfLots;
                if (inv % selectedMRP.getBom().getMaterial().getLotSize() == 0) {
                    numOfLots = inv / selectedMRP.getBom().getMaterial().getLotSize();
                } else {
                    numOfLots = inv / selectedMRP.getBom().getMaterial().getLotSize() + 1;
                }
                Long prevRec = selectedMRP.getPlannedReceipts().get(i).getLongValue();
                Long currentPlannedReceipt = prevRec + numOfLots * selectedMRP.getBom().getMaterial().getLotSize();
                selectedMRP.getPlannedReceipts().get(i).setLongValue(currentPlannedReceipt);
                inputLotNumbers.get(i).setL(numOfLots + prevRec / selectedMRP.getBom().getMaterial().getLotSize());
                for (int j = i; j < numOfWks; j++) {
                    Long prevInv;
                    if (j == 0) {
                        prevInv = mrpSession.getPlannedInventoryForPrevWeek(selectedMRP.getStartPeriodYear(), selectedMRP.getStartPeriodMonth(), selectedMRP.getBom());
                    } else {
                        prevInv = selectedMRP.getPlannedInventory().get(j - 1).getLongValue();
                    }
                    Long currentInv = prevInv + selectedMRP.getPlannedReceipts().get(j).getLongValue() - selectedMRP.getGrossRequirements().get(j).getLongValue();
                    selectedMRP.getPlannedInventory().get(j).setLongValue(currentInv);
                }
            }
        }
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Successful",
                "Optimization for this materials done."));
    }

    public void calculateMRP(ActionEvent event) {
        // substitute the onhand current value and planned receipts
        for (int i = 0; i < numOfWks; i++) {
            // set planned receipts
            selectedMRP.getPlannedReceipts().get(i).setLongValue(inputLotNumbers.get(i).getL() * selectedMRP.getBom().getMaterial().getLotSize());
            // set planned inventory
            Long prevInv;
            if (i == 0) {
                prevInv = returnPrevInventory();
            } else {
                prevInv = selectedMRP.getPlannedInventory().get(i - 1).getLongValue();
            }
            Long diff = prevInv + selectedMRP.getPlannedReceipts().get(i).getLongValue() - selectedMRP.getGrossRequirements().get(i).getLongValue();
            selectedMRP.getPlannedInventory().get(i).setLongValue(diff);
        }
        // check whether it is not negative
        for (int i = 0; i < numOfWks; i++) {
            if (selectedMRP.getGrossRequirements().get(i).getLongValue() < 0
                    || selectedMRP.getPlannedInventory().get(i).getLongValue() < 0
                    || selectedMRP.getPlannedReceipts().get(i).getLongValue() < 0) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                        "Sorry. On hand inventory cannot be negative. Please check week" + (i + 1)));
            }
        }
    }

    public MRP getSelectedMRP() {
        if (selectedMRP == null) {
            MRP mrp = (MRP) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(MrpMrpViewManagerBean.EDIT_MRP);
            if (mrp != null) {
                selectedMRP = mrp;
                weeklyDemands = mrpSession.getWeeklyDemands(selectedMRP.getStartPeriodYear(), selectedMRP.getStartPeriodMonth());
                if (weeklyDemands.get(0).get(4) == null) {
                    numOfWks = 4;
                } else {
                    numOfWks = 5;
                }
                inputLotNumbers = new ArrayList<LongHolder>();
                for (int i = 0; i < numOfWks; i++) {
                    LongHolder temp = new LongHolder();
                    temp.setL(selectedMRP.getPlannedReceipts().get(i).getLongValue() / selectedMRP.getBom().getMaterial().getLotSize());
                    inputLotNumbers.add(temp);
                }

            }
        }
        return selectedMRP;
    }

    public void setSelectedMRP(MRP selectedMRP) {
        this.selectedMRP = selectedMRP;
    }

    public ArrayList<ArrayList<Long>> getWeeklyDemands() {
        if (weeklyDemands == null) {
            weeklyDemands = mrpSession.getWeeklyDemands(selectedMRP.getStartPeriodYear(), selectedMRP.getStartPeriodMonth());
        }
        return weeklyDemands;
    }

    public void setWeeklyDemands(ArrayList<ArrayList<Long>> weeklyDemands) {
        this.weeklyDemands = weeklyDemands;
    }

    public ArrayList<LongHolder> getInputLotNumbers() {
        return inputLotNumbers;
    }

    public void setInputLotNumbers(ArrayList<LongHolder> inputLotNumbers) {
        this.inputLotNumbers = inputLotNumbers;
    }

    public Double returnKG(Long l, int productId) {
        if (l == null) {
            return null;
        }
        switch (productId) {
            case 0:
                return 12.0 * l * selectedMRP.getBom().getMaterialRequirements().get(productId).getValue();
            case 1:
                return 12.0 * l * selectedMRP.getBom().getMaterialRequirements().get(productId).getValue();
            case 2:
                return 13.32 * l * selectedMRP.getBom().getMaterialRequirements().get(productId).getValue();
            case 3:
                return 13.32 * l * selectedMRP.getBom().getMaterialRequirements().get(productId).getValue();
            default:
                return 0.0;
        }
    }

    public Long returnPrevInventory() {
        return mrpSession.getPlannedInventoryForPrevWeek(selectedMRP.getStartPeriodYear(), selectedMRP.getStartPeriodMonth(), selectedMRP.getBom());
    }

    public Long returnGrossRequirements(int dayid) {
        if (dayid + 1 > numOfWks) {
            return null;
        }
        return selectedMRP.getGrossRequirements().get(dayid).getLongValue();
    }

    public Integer getNumOfWks() {
        if (numOfWks == null) {
            if (getWeeklyDemands().get(0).get(4) == null) {
                numOfWks = 4;
            } else {
                numOfWks = 5;
            }
        }
        return numOfWks;
    }

    public ArrayList<ArrayList<Timestamp>> getStartEndDays() {
        if (startEndDays == null) {
            int pointedMonth = selectedMRP.getStartPeriodMonth();
            int pointedYear = selectedMRP.getStartPeriodYear().intValue();
            startEndDays = mpsSession.getStartEndDaysList(pointedMonth, pointedYear);
        }
        return startEndDays;
    }

    // for rendering
    public boolean renderEdit(LongHolder item) {
        boolean render = false;

        int index = inputLotNumbers.indexOf(item);
        if (index == -1) {
            return render;
        }
        
        Timestamp pointedTime = getStartEndDays().get(0).get(index);
        int pointedYear = Integer.valueOf(Consts.sdfYear.format(pointedTime));
        int pointedMonth = Integer.valueOf(Consts.sdfMonth.format(pointedTime));
        int pointedDay = Integer.valueOf(Consts.sdfDay.format(pointedTime));

        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();

        //  for testing
        //c2.set(2011, 11, 24);
        c1.set(pointedYear, pointedMonth - 1, pointedDay,0,0,0); // pointed planned time

        long millis1 = c1.getTimeInMillis();
        long millis2 = c2.getTimeInMillis(); // current time

        double d = (millis1 - millis2) / (24.0 * 60 * 60 * 1000);

        if (d > 7 * selectedMRP.getBom().getMaterial().getLeadtime() && millis1 - millis2 > 0) {
            render = true;
        }
        return render;
    }

    public boolean renderEmpty() {
        if (getNumOfWks() == 4) {
            return true;
        } else {
            return false;
        }
    }

    public boolean renderCell(Integer dayId) {
        if (dayId + 1 <= numOfWks) {
            return true;
        } else {
            return false;
        }
    }

//    public boolean renderCell() {
//        
//    }
    // for general purpose
    private String getRedirectPath(String path) {
        return path + "?faces-redirect=true";
    }

    public ArrayList<Integer> getCounterForProduct() {
        return counterForProduct;
    }

    public ArrayList<Integer> getCounterForWeek() {
        return counterForWeek;
    }

    public String returnProductName(Integer i) {
        if (i.intValue() == 0) {
            return Consts.ProductType.BAR_A.getText();
        } else if (i.intValue() == 1) {
            return Consts.ProductType.BAR_B.getText();
        } else if (i.intValue() == 2) {
            return Consts.ProductType.BAR_C.getText();
        } else if (i.intValue() == 3) {
            return Consts.ProductType.BAR_D.getText();
        } else {
            return "";
        }
    }

    public String getMonthEnglish(int i) {
        switch (i) {
            case 1:
                return Consts.JAN;
            case 2:
                return Consts.FEB;
            case 3:
                return Consts.MAR;
            case 4:
                return Consts.APR;
            case 5:
                return Consts.MAY;
            case 6:
                return Consts.JUN;
            case 7:
                return Consts.JUL;
            case 8:
                return Consts.AUG;
            case 9:
                return Consts.SEP;
            case 10:
                return Consts.OCT;
            case 11:
                return Consts.NOV;
            case 12:
                return Consts.DEC;
            default:
                return "";
        }
    }
}
